/*
 * ModFam.c
 *
 * Created: 20/03/2012 15:51:10
 *  Author: marionse
 */ 

#include <avr/io.h>
#include <avr/eeprom.h>

#include "ModCpu.h"
#include "ModFam.h"
#include "ModSysTimer.h"
#include "ModRF.h"

// inclus le fichier applicatif pour connaitre les familles presentes
#include "AppDesc.h"

/**
* \brief FONCTION PRIVEE DU MODULE
*/


/**
* \brief Variable eeprom permettant de connaitre l'etat du boot
*/
Int8U boot_ctrl_eeprom __attribute__ ((section (".rsvd_boot")));
/**
* \brief Variable eeprom commune a tous les applicatif pour savoir si une initialisation doit etre faite
*			ie si different de EEPROM_INITIALIZED (0x21)
*/
Int8U boot_clear_eeprom __attribute__ ((section (".rsvd_boot")));

/**
* \brief APP_HAVE_FAM_NONE_CALLBACK : permet de recevoir les messages de la famille NONE non traiter par le module
*/
#ifdef APP_HAVE_FAM_NONE_CALLBACK
	void ModFamNoneCallback( TRFMsg *ip_msg );
#endif // APP_HAVE_FAM_NONE_CALLBACK

/**
* \brief fonction d'initialisation du module
*/
ERetCode ModFamInit( void )
{
	ERetCode lo_ret_code = E_RET_SUCCESS;
	
	/** traite le bootloader */
	if( ModFamReadBootCtrl() >= E_BOOT_NB_STATE )
	{
		ModFamWriteBootCtrl( E_BOOT_APP);		
	}
	/** on envoi un ACK avec le l'ID applicatif */
	ModFamSendACK( RF_BRD_ADDR );
	
	
	/** initialise les differente famille */
#ifdef FAMGENERAL_H_
	if( E_RET_SUCCESS == lo_ret_code )
	{
		lo_ret_code = FamGeneralInit();	
	}
#endif
#ifdef FAMSERVO_H_
	if( E_RET_SUCCESS == lo_ret_code )
	{
		lo_ret_code = FamServoInit();	
	}
#endif
	
	return lo_ret_code;
}

/**
* \brief fonction appelee a chaque passage dans la boucle main
*/
ERetCode ModFamTick( void )
{
	ERetCode lo_ret_code = E_RET_SUCCESS;

	TRFMsg l_in_msg;	
	
	// tick famille
#ifdef FAMGENERAL_H_
	if( E_RET_SUCCESS == lo_ret_code )
	{
		lo_ret_code = FamGeneralTick();	
	}
#endif
#ifdef FAMSERVO_H_
	if( E_RET_SUCCESS == lo_ret_code )
	{
		lo_ret_code = FamServoTick();	
	}
#endif

	// reception
	if( E_RET_SUCCESS == lo_ret_code )
	{
		if( E_RET_SUCCESS == modRFGetMsg( &l_in_msg ) )
		{
			// on va passer le message a la bonne famille	
			if( E_FAM_NONE == l_in_msg.msg.family_id )
			{
				/** on traite le minimum de commande */
				switch( l_in_msg.msg.cmd_id )
				{
					case FAM_NONE_CMD_START_BOOTLOADER_ID:
					{
						/** si on est en mode app on on bascule en start et on reset */ 
						if( E_BOOT_APP == ModFamReadBootCtrl() )
						{
							ModFamWriteBootCtrl( E_BOOT_START);
							ModCpuReset();
						}
						else
						{
							/** si une callback existe on l'appel */
							#ifdef APP_HAVE_FAM_NONE_CALLBACK
								ModFamNoneCallback( &l_in_msg );
							#else
								ModFamSendNACK( l_in_msg.src_addr );
							#endif // APP_HAVE_FAM_NONE_CALLBACK
						}
					}
					break;
					
					case FAM_NONE_CMD_RESET_ID:
					{
						// le reset peut toujours avoir lieu
						ModCpuReset();
					}
					break;
					
					case FAM_NONE_CMD_GET_APP_ID:
					{
						ModFamSendACK( l_in_msg.src_addr );
					}
					break;
					
					default:
					{
						/** si une callback existe on l'appel */
						#ifdef APP_HAVE_FAM_NONE_CALLBACK
							ModFamNoneCallback( &l_in_msg );
						#endif // APP_HAVE_FAM_NONE_CALLBACK
					}
					break;
				}
			}				
#ifdef FAMGENERAL_H_
			if( E_FAM_GENERAL_ID == l_in_msg.msg.family_id )
			{
				lo_ret_code = FamGeneralInMsg( &l_in_msg );	
			}
#endif
#ifdef FAMSERVO_H_
			if( E_FAM_SERVO == l_in_msg.msg.family_id )
			{
				lo_ret_code = FamServoInMsg( &l_in_msg );	
			}
#endif
		}
	}		
	
	return lo_ret_code;
}

/**
* \brief fonction simple pour envoyer un ACK
*
* \param[IN] i_dest_addr : addresse de destination
*/
void ModFamSendACK( Int16U i_dest_addr )
{
	SFamMsg msg;

	msg.family_id = E_FAM_NONE;
	msg.cmd_id = FAM_NONE_CMD_ACK_ID;
	msg.len = FAM_NONE_CMD_ACK_PAYLOAD_SIZE;
	msg.payload[FAM_NONE_CMD_ACK_ARG_ID_IDX] = APP_ID;
					
	modRFSendMsg( &msg, i_dest_addr );
}

/**
* \brief fonction simple pour envoyer un NACK
*
* \param[IN] i_dest_addr : addresse de destination
*/
void ModFamSendNACK( Int16U i_dest_addr )
{
	SFamMsg msg;

	msg.family_id = E_FAM_NONE;
	msg.cmd_id = FAM_NONE_CMD_NACK_ID;
	msg.len = FAM_NONE_CMD_NACK_PAYLOAD_SIZE;
	msg.payload[FAM_NONE_CMD_NACK_ARG_ID_IDX] = APP_ID;
					
	modRFSendMsg( &msg, i_dest_addr );
}

/** lecture */
EBootloaderCtrl ModFamReadBootCtrl( void )
{
	return eeprom_read_byte((Int8U*)&boot_ctrl_eeprom);
}

/** ecriture */
void ModFamWriteBootCtrl( EBootloaderCtrl i_boot_ctrl )
{
	if( i_boot_ctrl != eeprom_read_byte((Int8U*)&boot_ctrl_eeprom) )
	{
		eeprom_write_byte((Int8U*)&boot_ctrl_eeprom, i_boot_ctrl);		
	}
}

/** lecture */
EBootloaderCtrl ModFamReadBootClearEeprom( void )
{
	return eeprom_read_byte((Int8U*)&boot_clear_eeprom);
}

/** ecriture */
void ModFamWriteBootClearEeprom( Int8U i_value )
{
	if( i_value != eeprom_read_byte((Int8U*)&boot_clear_eeprom) )
	{
		eeprom_write_byte((Int8U*)&boot_clear_eeprom, i_value);		
	}
}